//! Protocol handlers
//! 
//! This module contains protocol-specific implementations for different
//! types of testing (HTTP, WebSocket, gRPC, etc.).

pub mod http;
pub mod websocket;
pub mod grpc;
pub mod graphql;

use crate::error::Result;
use crate::models::{
    step::{StepResult, StepContext},
    request::{HttpRequest, HttpResponse},
    Value, ValueMap,
};
use async_trait::async_trait;
use uuid::Uuid;

/// Protocol handler trait
#[async_trait]
pub trait ProtocolHandler: Send + Sync {
    /// Get protocol name
    fn protocol_name(&self) -> &str;
    
    /// Get supported operations
    fn supported_operations(&self) -> Vec<String>;
    
    /// Execute a protocol-specific operation
    async fn execute(&self, operation: &str, params: ValueMap, context: &mut StepContext) -> Result<StepResult>;
    
    /// Validate operation parameters
    fn validate_params(&self, operation: &str, params: &ValueMap) -> Result<()>;
    
    /// Initialize the handler
    async fn initialize(&mut self, config: ValueMap) -> Result<()> {
        Ok(())
    }
    
    /// Cleanup the handler
    async fn cleanup(&mut self) -> Result<()> {
        Ok(())
    }
}

/// Protocol manager for handling different protocols
pub struct ProtocolManager {
    /// Registered protocol handlers
    handlers: std::collections::HashMap<String, Box<dyn ProtocolHandler>>,
}

impl ProtocolManager {
    /// Create a new protocol manager
    pub fn new() -> Self {
        let mut manager = Self {
            handlers: std::collections::HashMap::new(),
        };
        
        // Register default protocol handlers
        manager.register_default_handlers();
        manager
    }
    
    /// Register default protocol handlers
    fn register_default_handlers(&mut self) {
        // Register HTTP handler
        let http_handler = http::HttpProtocolHandler::new();
        self.handlers.insert(http_handler.protocol_name().to_string(), Box::new(http_handler));
        
        // Register WebSocket handler
        let ws_handler = websocket::WebSocketProtocolHandler::new();
        self.handlers.insert(ws_handler.protocol_name().to_string(), Box::new(ws_handler));
        
        // Register gRPC handler
        let grpc_handler = grpc::GrpcProtocolHandler::new();
        self.handlers.insert(grpc_handler.protocol_name().to_string(), Box::new(grpc_handler));
        
        // Register GraphQL handler
        let graphql_handler = graphql::GraphQLProtocolHandler::new();
        self.handlers.insert(graphql_handler.protocol_name().to_string(), Box::new(graphql_handler));
    }
    
    /// Register a protocol handler
    pub fn register_handler(&mut self, handler: Box<dyn ProtocolHandler>) {
        let protocol_name = handler.protocol_name().to_string();
        self.handlers.insert(protocol_name, handler);
    }
    
    /// Get a protocol handler
    pub fn get_handler(&self, protocol: &str) -> Option<&dyn ProtocolHandler> {
        self.handlers.get(protocol).map(|h| h.as_ref())
    }
    
    // TODO: Fix lifetime issues with mutable protocol handler access
    // pub fn get_handler_mut(&mut self, protocol: &str) -> Option<&mut (dyn ProtocolHandler + '_)> {
    //     self.handlers.get_mut(protocol).map(move |h| h.as_mut())
    // }
    
    /// Execute a protocol operation
    pub async fn execute(
        &self,
        protocol: &str,
        operation: &str,
        params: ValueMap,
        context: &mut StepContext,
    ) -> Result<StepResult> {
        let handler = self.get_handler(protocol)
            .ok_or_else(|| crate::error::Error::Internal(
                format!("Protocol handler not found: {}", protocol)
            ))?;
        
        // Validate parameters
        handler.validate_params(operation, &params)?;
        
        // Execute operation
        handler.execute(operation, params, context).await
    }
    
    /// List all registered protocols
    pub fn list_protocols(&self) -> Vec<&str> {
        self.handlers.keys().map(|s| s.as_str()).collect()
    }
    
    /// Get protocol operations
    pub fn get_protocol_operations(&self, protocol: &str) -> Option<Vec<String>> {
        self.get_handler(protocol).map(|h| h.supported_operations())
    }
    
    /// Initialize all handlers
    pub async fn initialize_all(&mut self, global_config: ValueMap) -> Result<()> {
        for (protocol, handler) in &mut self.handlers {
            tracing::info!("Initializing protocol handler: {}", protocol);
            
            // Extract protocol-specific config
            let protocol_config = global_config.get(protocol)
                .and_then(|v| v.as_object())
                .map(|obj| obj.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
                .unwrap_or_default();
            
            handler.initialize(protocol_config).await?;
        }
        
        Ok(())
    }
    
    /// Cleanup all handlers
    pub async fn cleanup_all(&mut self) -> Result<()> {
        for (protocol, handler) in &mut self.handlers {
            tracing::info!("Cleaning up protocol handler: {}", protocol);
            handler.cleanup().await?;
        }
        
        Ok(())
    }
}

impl Default for ProtocolManager {
    fn default() -> Self {
        Self::new()
    }
}

/// Protocol operation result
#[derive(Debug, Clone)]
pub struct ProtocolResult {
    /// Operation that was executed
    pub operation: String,
    
    /// Protocol used
    pub protocol: String,
    
    /// Execution success
    pub success: bool,
    
    /// Response data
    pub data: Option<Value>,
    
    /// Error message if failed
    pub error: Option<String>,
    
    /// Execution duration in milliseconds
    pub duration: u64,
    
    /// Additional metadata
    pub metadata: ValueMap,
}

impl ProtocolResult {
    /// Create a successful result
    pub fn success(protocol: String, operation: String, data: Option<Value>, duration: u64) -> Self {
        Self {
            operation,
            protocol,
            success: true,
            data,
            error: None,
            duration,
            metadata: std::collections::HashMap::new(),
        }
    }
    
    /// Create a failed result
    pub fn failure(protocol: String, operation: String, error: String, duration: u64) -> Self {
        Self {
            operation,
            protocol,
            success: false,
            data: None,
            error: Some(error),
            duration,
            metadata: std::collections::HashMap::new(),
        }
    }
    
    /// Add metadata
    pub fn with_metadata(mut self, metadata: ValueMap) -> Self {
        self.metadata = metadata;
        self
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_protocol_manager_creation() {
        let manager = ProtocolManager::new();
        
        // Should have default protocols registered
        let protocols = manager.list_protocols();
        assert!(protocols.contains(&"http"));
        assert!(protocols.contains(&"websocket"));
        assert!(protocols.contains(&"grpc"));
        assert!(protocols.contains(&"graphql"));
    }

    #[test]
    fn test_protocol_result() {
        let result = ProtocolResult::success(
            "http".to_string(),
            "request".to_string(),
            Some(serde_json::json!({"status": "ok"})),
            100,
        );
        
        assert!(result.success);
        assert_eq!(result.protocol, "http");
        assert_eq!(result.operation, "request");
        assert_eq!(result.duration, 100);
    }
}
